#if defined(_WIN32)
#include <windows.h>
#include <time.h>
#endif

#if defined(_LINUX)
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <pthread.h>
#endif

#include "Utility.h"

#if defined(_WIN32)
struct _PTTime
{
	unsigned long  time;     // seconds
	unsigned short millitm;  // milliseconds
	short          timezone; // difference in minutes, moving westward, between UTC and local time.
	short          dstflag;  // nonzero if Daylight Saving Time is currently in effect for the local time zone.
};

extern "C" void _ftime(_PTTime* time);
#endif

unsigned long CUtility::EpochTime(void)
{
#if defined(_WIN32)
	_PTTime time;
	_ftime(&time);

	return time.time;

#elif defined(_LINUX)
	struct timeval time;
	gettimeofday(&time, NULL);

	return (unsigned long)time.tv_sec;
#endif
}

unsigned short CUtility::MilliSec(void)
{
#if defined(_WIN32)
	_PTTime time;
	_ftime(&time);

	return time.millitm;

#elif defined(_LINUX)
	struct timeval time;
	gettimeofday(&time, NULL);

	return (unsigned long)time.millitm;
#endif
}

void CUtility::BinaryToDate(unsigned long nBinary, stTimeset &dateTime, TIMEZONE timeZone)
{
	unsigned long hour;
	unsigned long day;
	unsigned long minute;
	unsigned long second;
	unsigned long month;
	unsigned long year;

	unsigned long whole_minutes;
	unsigned long whole_hours;
	unsigned long whole_days;
	unsigned long whole_days_since_1968;
	unsigned long leap_year_periods;
	unsigned long days_since_current_lyear;
	unsigned long whole_years;
	unsigned long days_since_first_of_year;
	unsigned long days_to_month;
	unsigned long day_of_week;

	nBinary += timeZone * ONEHOUR_SEC;

	whole_minutes = nBinary / ONEMIN_SEC;
	second		  = nBinary - (ONEMIN_SEC * whole_minutes);			// leftover seconds

	whole_hours	  = whole_minutes / ONEHOUR_MIN;
	minute		  = whole_minutes - (ONEHOUR_MIN * whole_hours);	// leftover minutes

	whole_days    = whole_hours / ONEDAY_HOUR;
	hour          = whole_hours - (ONEDAY_HOUR * whole_days);		// leftover hours

	whole_days_since_1968 = whole_days + ONEYEAR_DAY + 366;
	leap_year_periods = whole_days_since_1968 / ((4 * ONEYEAR_DAY) + 1);

	days_since_current_lyear = whole_days_since_1968 % ((4 * ONEYEAR_DAY) + 1);

	// if days are after a current leap year then add a leap year period
	if((days_since_current_lyear >= (31 + 29))) 
		leap_year_periods++;

	whole_years = (whole_days_since_1968 - leap_year_periods) / ONEYEAR_DAY;
	days_since_first_of_year = whole_days_since_1968 - 
							   (whole_years * ONEYEAR_DAY) - 
							   leap_year_periods;

	if((days_since_current_lyear <= ONEYEAR_DAY) && 
		(days_since_current_lyear >= 60)) 
		days_since_first_of_year++;

	year = whole_years + 68;	

	// setup for a search for what month it is based on how many days have past
	// within the current year
	month			= 13;
	days_to_month	= ONEYEAR_DAY;

	while(days_since_first_of_year < days_to_month) 
	{
		month--;
		days_to_month = m_ConvertDays2Mon(month);

		if ((month >= 2) && ((year % 4) == 0)) 
			days_to_month++;
	}
	day = days_since_first_of_year - days_to_month + 1;

	day_of_week = (whole_days + 4) % DAYS_WEEK;

	dateTime = stTimeset(second, minute, hour, day, 
						 ++month, year + BASIC_YEAR,
						 day_of_week, days_since_first_of_year);
	
	return;
}

unsigned int CUtility::Convert2Hour(stTimeset dateTime)
{
	unsigned int hours = 0;

	hours = (dateTime.tm_year * ONEYEAR_HOUR) + 
			(dateTime.tm_yday * ONEDAY_HOUR) + 
			dateTime.tm_hour;

	return hours;
}

unsigned long CUtility::m_ConvertDays2Mon(unsigned int nDays)
{
	if(nDays > 13)
		return 0;

	unsigned long nDaysToMonth[13] = 
	{
		0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
	};

	return nDaysToMonth[nDays];
}

